package server

import (
	"bytes"
	"dag2.0/gat1400-proxy/db"
	"dag2.0/gat1400-proxy/logger"
	"dag2.0/gat1400-proxy/model"
	"dag2.0/gat1400-proxy/model/constant"
	"dag2.0/gat1400-proxy/util"
	"dag2.0/gat1400-proxy/util/times"
	"fmt"
	"github.com/gin-gonic/gin"
	jsoniter "github.com/json-iterator/go"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)
import "github.com/360EntSecGroup-Skylar/excelize/v2"

var statusDic = make(map[string]string)

const (
	DELETE_RESOURCE_TYPE_EQUIPMENT = "1"
	DELETE_RESOURCE_TYPE_TOLLGATE  = "2"
)

func init() {
	statusDic["正常"] = "1"
	statusDic["停用"] = "2"
	statusDic["其他"] = "9"
}

func DeleteFormExcel(ctx *gin.Context) {
	fh, err := ctx.FormFile("file")
	if nil != err {
		logger.LOG_ERROR("找不到文件：", err)
		ctx.JSON(http.StatusOK, util.GenErrorMsg("找不到文件"))
		return
	}

	fmt.Println("file:", fh.Filename)
	if -1 == strings.Index(fh.Filename, ".xlsx") {
		logger.LOG_ERROR("文件格式不合法", err)
		ctx.JSON(http.StatusOK, util.GenErrorMsg("文件格式不合法：只能使用后缀为xlsx的文件"))
		return
	}

	f, err := fh.Open()
	if nil != err {
		logger.LOG_ERROR("打开文件失败：", err)
		ctx.JSON(http.StatusOK, util.GenErrorMsg("打开文件失败，文件地址："+fh.Filename))
		return
	}
	excelBytes, err := ioutil.ReadAll(f)
	if nil != err {
		logger.LOG_ERROR("读取文件失败：", err)
		ctx.JSON(http.StatusOK, util.GenErrorMsg("读取文件失败，文件地址："+fh.Filename))
		return
	}
	managerId := ctx.PostForm("managerId")
	selfManagerId := ctx.PostForm("selfManagerId")
	resourceType := ctx.PostForm("resourceType")
	fmt.Println(managerId)
	fmt.Println(selfManagerId)

	subscribeInfo := getSubscribeInfo(managerId)

	if DELETE_RESOURCE_TYPE_EQUIPMENT == resourceType {
		DeleteEquipmentFormExcel(ctx, subscribeInfo, excelBytes, selfManagerId)
	}

	if DELETE_RESOURCE_TYPE_TOLLGATE == resourceType {
		DeleteTollgateFormExcel(ctx, subscribeInfo, excelBytes, selfManagerId)
	}

}

func DeleteTollgateFormExcel(ctx *gin.Context, subscribeInfo map[string][]*model.Subscribe, excelBytes []byte, selfManagerId string) {
	sendSize := 0
	subscribeTollgates := subscribeInfo["TOLLGATE"]
	if nil != subscribeTollgates && len(subscribeTollgates) > 0 {
		for _, subscribeTollgate := range subscribeTollgates {
			notificationModelTollgate := genTollgateNotificationModel(excelBytes, subscribeTollgate.SubscribeID, subscribeTollgate.Title)
			sendSize += sendNotify(notificationModelTollgate, subscribeTollgate, selfManagerId)
		}
	}
	subscribeEquipments := subscribeInfo["EQUIPMENT"]
	if nil != subscribeEquipments && len(subscribeEquipments) > 0 {
		for _, subscribeEquipment := range subscribeEquipments {
			notificationModelEquipment := genApeNotificationModel(excelBytes, subscribeEquipment.SubscribeID, subscribeEquipment.Title, DELETE_RESOURCE_TYPE_TOLLGATE)
			sendSize += sendNotify(notificationModelEquipment, subscribeEquipment, selfManagerId)
		}
	}
	subscribeLanes := subscribeInfo["LANE"]
	if nil != subscribeLanes && len(subscribeLanes) > 0 {
		for _, subscribeLane := range subscribeLanes {
			notificationModelLane := genLaneNotificationModel(excelBytes, subscribeLane.SubscribeID, subscribeLane.Title)
			sendSize += sendNotify(notificationModelLane, subscribeLane, selfManagerId)
		}
	}
	ctx.JSON(http.StatusOK, map[string]interface{}{
		"code":    http.StatusOK,
		"message": "操作成功",
		"success": true,
		"data":    fmt.Sprintf("发送设备通知成功，通知个数为：%d", sendSize),
	})
	return
}

func DeleteEquipmentFormExcel(ctx *gin.Context, subscribeInfo map[string][]*model.Subscribe, excelBytes []byte, selfManagerId string) {
	sendSize := 0
	subscribeEquipments := subscribeInfo["EQUIPMENT"]
	if nil != subscribeEquipments && len(subscribeEquipments) > 0 {
		for _, subscribeEquipment := range subscribeEquipments {
			notificationModelEquipment := genApeNotificationModel(excelBytes, subscribeEquipment.SubscribeID, subscribeEquipment.Title, DELETE_RESOURCE_TYPE_EQUIPMENT)
			sendSize += sendNotify(notificationModelEquipment, subscribeEquipment, selfManagerId)
		}
	}
	ctx.JSON(http.StatusOK, map[string]interface{}{
		"code":    http.StatusOK,
		"message": "操作成功",
		"success": true,
		"data":    fmt.Sprintf("发送设备通知成功，通知个数为：%d", sendSize),
	})
	return
}

func sendNotify(models []*model.SubscribeNotificationModel, s *model.Subscribe, selfManagerId string) int {
	if nil == models || len(models) == 0 {
		return 0
	}

	//发送通知请求
	for _, subscribeNotificationModel := range models {
		i := 1
		jsonData, _ := jsoniter.Marshal(subscribeNotificationModel)
		logger.LOG_WARN("批量删除资源通知 url=", s.ReceiveAddr, " selfManagerId=", selfManagerId)
		logger.LOG_WARN("发送第", strconv.Itoa(i), "次通知, 通知结构为 ：", string(jsonData))
		res, _, _, e := util.Request(s.ReceiveAddr, http.MethodPost, map[string]string{
			"User-Identify": selfManagerId,
			"Content-Type":  "application/VIID+JSON",
		}, subscribeNotificationModel, nil)
		if e != nil {
			logger.LOG_ERROR("发送设备通知失败", e)
			continue
		}
		response := model.AnalyzeRsponseContent(res)
		resJson, _ := jsoniter.Marshal(response)
		//失败
		if response == nil || len(response.ResponseStatusListObject.ResponseStatusObject) <= 0 ||
			response.ResponseStatusListObject.ResponseStatusObject[0] == nil ||
			response.ResponseStatusListObject.ResponseStatusObject[0].StatusCode != model.OK {
			logger.LOG_ERROR("发送设备通知失败 ", util.BytesString(resJson)) //等待下次重新发送
			continue
		}
		i++
		logger.LOG_WARN("发送设备通知成功，返回数据为：", util.BytesString(resJson))
	}
	//成功时改变内存与数据库的数据状态
	logger.LOG_WARN("发送设备通知成功，通知个数为：", len(models))
	return len(models)
}

func genTollgateNotificationModel(file []byte, subscribeID string, title string) []*model.SubscribeNotificationModel {
	f, err := excelize.OpenReader(bytes.NewReader(file))
	if err != nil {
		fmt.Println(err)
		return nil
	}

	tollgates, _ := getTollgatesFormExcel(f)
	if len(tollgates) == 0 {
		return nil
	}

	var subscribeNotificationList = make([]*model.SubscribeNotification, 0)
	var subscribeNotificationModels = make([]*model.SubscribeNotificationModel, 0)

	subscribeNotification := &model.SubscribeNotification{
		NotificationID:   util.GenerateSubscribeNotificationID(),
		SubscribeID:      subscribeID,
		Title:            title,
		TriggerTime:      times.Time2StrWithFormat(times.DateFormatNoSpan),
		InfoIDs:          "",
		ExecuteOperation: EXECUTE_OPERATION_DEL,
	}

	batchSize := 30

	//小于组批大小，直接返回
	if len(tollgates) < batchSize {
		for _, v := range tollgates {
			subscribeNotification.InfoIDs += v.TollgateID
		}
		subscribeNotification.TollgateObjectList = &model.TollgateListObjectEntity{TollgateObject: tollgates}
		subscribeNotificationList = append(subscribeNotificationList, subscribeNotification)
		subscribeNotificationModel := &model.SubscribeNotificationModel{
			SubscribeNotificationListObject: &model.SubscribeNotificationListObject{SubscribeNotificationObject: subscribeNotificationList},
		}
		subscribeNotificationModels = append(subscribeNotificationModels, subscribeNotificationModel)
		return subscribeNotificationModels
	}

	if len(tollgates) > 0 {
		logger.LOG_WARN("共包含卡口集合个数为 ：", len(tollgates))
		batchDeal(len(tollgates), batchSize, func(start, end int) {
			logger.LOG_WARN(fmt.Sprintf("拆分卡口集合index为：start ：%d,end :%d", start, end))
			func(tollgatesf []*model.Tollgate) {
				tempSubscribeNotification := *subscribeNotification
				subscribeNotification := &tempSubscribeNotification
				subscribeNotification.TriggerTime = times.Time2StrWithFormat(times.DateFormatNoSpan)
				subscribeNotification.TollgateObjectList = &model.TollgateListObjectEntity{TollgateObject: tollgatesf}
				for _, v := range tollgatesf {
					subscribeNotification.InfoIDs += v.TollgateID
				}
				subscribeNotificationList = append(subscribeNotificationList, subscribeNotification)
			}(tollgates[start:end])
		})
	}

	for _, subscribeNotification := range subscribeNotificationList {
		subscribeNotificationModel := &model.SubscribeNotificationModel{
			SubscribeNotificationListObject: &model.SubscribeNotificationListObject{SubscribeNotificationObject: []*model.SubscribeNotification{subscribeNotification}},
		}
		subscribeNotificationModels = append(subscribeNotificationModels, subscribeNotificationModel)
	}
	return subscribeNotificationModels
}

func genLaneNotificationModel(file []byte, subscribeID string, title string) []*model.SubscribeNotificationModel {
	f, err := excelize.OpenReader(bytes.NewReader(file))
	if err != nil {
		fmt.Println(err)
		return nil
	}

	lanes, _ := getLanesFormExcel(f)
	if len(lanes) == 0 {
		return nil
	}

	var subscribeNotificationList = make([]*model.SubscribeNotification, 0)
	var subscribeNotificationModels = make([]*model.SubscribeNotificationModel, 0)

	subscribeNotification := &model.SubscribeNotification{
		NotificationID:   util.GenerateSubscribeNotificationID(),
		SubscribeID:      subscribeID,
		Title:            title,
		TriggerTime:      times.Time2StrWithFormat(times.DateFormatNoSpan),
		InfoIDs:          "",
		ExecuteOperation: EXECUTE_OPERATION_DEL,
	}

	batchSize := 30

	//小于组批大小，直接返回
	if len(lanes) < batchSize {
		subscribeNotification.LaneObjectList = &model.LaneListObjectEntity{LaneObject: lanes}
		for _, v := range lanes {
			subscribeNotification.InfoIDs += strconv.Itoa(v.LaneId)
		}

		subscribeNotificationList = append(subscribeNotificationList, subscribeNotification)

		subscribeNotificationModel := &model.SubscribeNotificationModel{
			SubscribeNotificationListObject: &model.SubscribeNotificationListObject{SubscribeNotificationObject: subscribeNotificationList},
		}
		subscribeNotificationModels = append(subscribeNotificationModels, subscribeNotificationModel)
		return subscribeNotificationModels
	}

	if len(lanes) > 0 {
		logger.LOG_WARN("共包含车道集合个数为 ：", len(lanes))
		batchDeal(len(lanes), batchSize, func(start, end int) {
			logger.LOG_WARN(fmt.Sprintf("拆分车道集合index为：start ：%d,end :%d", start, end))
			func(lanesf []*model.Lane) {
				tempSubscribeNotification := *subscribeNotification
				subscribeNotification := &tempSubscribeNotification
				subscribeNotification.TriggerTime = times.Time2StrWithFormat(times.DateFormatNoSpan)
				subscribeNotification.LaneObjectList = &model.LaneListObjectEntity{LaneObject: lanesf}
				for _, v := range lanesf {
					subscribeNotification.InfoIDs += strconv.Itoa(v.LaneId)
				}
				subscribeNotificationList = append(subscribeNotificationList, subscribeNotification)
			}(lanes[start:end])
		})
	}

	for _, subscribeNotification := range subscribeNotificationList {
		subscribeNotificationModel := &model.SubscribeNotificationModel{
			SubscribeNotificationListObject: &model.SubscribeNotificationListObject{SubscribeNotificationObject: []*model.SubscribeNotification{subscribeNotification}},
		}
		subscribeNotificationModels = append(subscribeNotificationModels, subscribeNotificationModel)
	}
	return subscribeNotificationModels
}

func genApeNotificationModel(file []byte, subscribeID string, title string, eqType string) []*model.SubscribeNotificationModel {
	f, err := excelize.OpenReader(bytes.NewReader(file))
	if err != nil {
		fmt.Println(err)
		return nil
	}
	var apes []*model.APE
	if DELETE_RESOURCE_TYPE_EQUIPMENT == eqType {
		apes, _ = getEquipmentsFormExcel(f)
	}
	if DELETE_RESOURCE_TYPE_TOLLGATE == eqType {
		//卡口设备
		apes, _ = getApesFormExcel(f)
	}
	if nil == apes || len(apes) == 0 {
		return nil
	}

	var subscribeNotificationList = make([]*model.SubscribeNotification, 0)
	var subscribeNotificationModels = make([]*model.SubscribeNotificationModel, 0)

	subscribeNotification := &model.SubscribeNotification{
		NotificationID:   util.GenerateSubscribeNotificationID(),
		SubscribeID:      subscribeID,
		Title:            title,
		TriggerTime:      times.Time2StrWithFormat(times.DateFormatNoSpan),
		InfoIDs:          "",
		ExecuteOperation: EXECUTE_OPERATION_DEL,
	}

	batchSize := 30

	//小于组批大小，直接返回
	if len(apes) < batchSize {
		for _, v := range apes {
			subscribeNotification.InfoIDs += v.ApeID
		}
		subscribeNotification.DeviceList = &model.APEListObjectEntity{APEObject: apes}
		subscribeNotificationList = append(subscribeNotificationList, subscribeNotification)

		subscribeNotificationModel := &model.SubscribeNotificationModel{
			SubscribeNotificationListObject: &model.SubscribeNotificationListObject{SubscribeNotificationObject: subscribeNotificationList},
		}
		subscribeNotificationModels = append(subscribeNotificationModels, subscribeNotificationModel)
		return subscribeNotificationModels
	}
	batchDeal(len(apes), batchSize, func(start, end int) {
		logger.LOG_WARN(fmt.Sprintf("拆分设备集合index为：start ：%d,end :%d", start, end))
		func(apesf []*model.APE) {
			tempSubscribeNotification := *subscribeNotification
			subscribeNotification := &tempSubscribeNotification
			subscribeNotification.TriggerTime = times.Time2StrWithFormat(times.DateFormatNoSpan)
			subscribeNotification.DeviceList = &model.APEListObjectEntity{APEObject: apesf}
			for _, v := range apesf {
				subscribeNotification.InfoIDs += v.ApeID
			}

			subscribeNotificationList = append(subscribeNotificationList, subscribeNotification)
		}(apes[start:end])
	})

	for _, subscribeNotification := range subscribeNotificationList {
		subscribeNotificationModel := &model.SubscribeNotificationModel{
			SubscribeNotificationListObject: &model.SubscribeNotificationListObject{SubscribeNotificationObject: []*model.SubscribeNotification{subscribeNotification}},
		}
		subscribeNotificationModels = append(subscribeNotificationModels, subscribeNotificationModel)
	}
	return subscribeNotificationModels
}

func getTollgatesFormExcel(file *excelize.File) ([]*model.Tollgate, error) {
	rows, err := file.GetRows("卡口信息")
	if err != nil {
		logger.LOG_ERROR(err)
		return nil, err
	}
	if len(rows) <= 1 {
		return nil, nil
	}
	logger.LOG_WARN("卡口信息sheet读取行数：", len(rows))
	var tollgates = make([]*model.Tollgate, 0)
	for idx, row := range rows {
		if 0 == idx {
			continue
		}
		if len(row) < 12 {
			continue
		}
		//gbid
		tollgateID := row[1]
		if "" == tollgateID {
			continue
		}
		longitude, _ := strconv.ParseFloat(row[10], 64)
		latitude, _ := strconv.ParseFloat(row[11], 64)
		tollgateUsage, _ := strconv.Atoi(row[9])

		statusCode := statusDic[row[7]]
		if "" == statusCode {
			statusCode = "9"
		}

		var t = &model.Tollgate{
			TollgateID:    tollgateID,
			Name:          row[0],
			Longitude:     longitude,
			Latitude:      latitude,
			PlaceCode:     row[6],
			Place:         "",
			Status:        statusCode,
			TollgateCat:   "99",
			TollgateUsage: tollgateUsage,
			LaneNum:       0,
			OrgCode:       row[5],
			ActiveTime:    "",
		}
		tollgates = append(tollgates, t)
	}
	logger.LOG_WARN("tollgates size=", len(tollgates))
	return tollgates, nil
}

func getLanesFormExcel(file *excelize.File) ([]*model.Lane, error) {
	rows, err := file.GetRows("车道信息")
	if err != nil {
		logger.LOG_ERROR(err)
		return nil, err
	}
	if len(rows) <= 1 {
		return nil, nil
	}
	logger.LOG_WARN("车道信息sheet读取行数：", len(rows))
	var lanes = make([]*model.Lane, 0)
	for idx, row := range rows {
		if 0 == idx {
			continue
		}

		if len(row) < 7 {
			continue
		}

		apeID := row[6]
		if "" == apeID {
			//不删设备id为空的车道
			continue
		}

		laneNo, _ := strconv.Atoi(row[4])

		var t = &model.Lane{
			LaneNo:     laneNo,
			TollgateID: row[1],
			Name:       row[0],
			Direction:  row[5],
			Desc:       "",
			MaxSpeed:   0,
			CityPass:   0,
			ApeID:      apeID,
		}
		lanes = append(lanes, t)
	}
	logger.LOG_WARN("lanes size=", len(lanes))
	return lanes, nil
}

// 卡口设备
func getApesFormExcel(file *excelize.File) ([]*model.APE, error) {
	rows, err := file.GetRows("设备信息")
	if err != nil {
		logger.LOG_ERROR(err)
		return nil, err
	}
	if len(rows) <= 1 {
		return nil, nil
	}
	logger.LOG_WARN("设备信息sheet读取行数：", len(rows))
	var apes = make([]*model.APE, 0)
	for idx, row := range rows {
		if 0 == idx {
			continue
		}

		if len(row) < 14 {
			continue
		}
		//gbid
		apeID := row[2]
		if "" == apeID {
			//不删设备id为空的
			continue
		}

		port, _ := strconv.Atoi(row[6])
		var t = &model.APE{
			ApeID:            apeID,
			Name:             row[0],
			Model:            row[13],
			IPAddr:           row[4],
			IPV6Addr:         "",
			Port:             port,
			Longitude:        0,
			Latitude:         0,
			PlaceCode:        row[11],
			Place:            "",
			OrgCode:          row[10],
			CapDirection:     0,
			MonitorDirection: "",
			MonitorAreaDesc:  "",
			IsOnline:         "",
			OwnerApsID:       "",
			UserId:           row[7],
			Password:         row[8],
			FunctionType:     "",
			PositionType:     "",
			TollgateID:       "",
			AreaType:         "",
			PassDirection:    "",
		}
		apes = append(apes, t)
	}
	logger.LOG_WARN("apes size=", len(apes))
	return apes, nil
}

// 采集设备
func getEquipmentsFormExcel(file *excelize.File) ([]*model.APE, error) {
	rows, err := file.GetRows("设备信息")
	if err != nil {
		logger.LOG_ERROR(err)
		return nil, err
	}
	if len(rows) <= 1 {
		return nil, nil
	}
	logger.LOG_WARN("设备信息sheet读取行数：", len(rows))
	var apes = make([]*model.APE, 0)
	for idx, row := range rows {
		if 0 == idx {
			continue
		}

		if len(row) < 27 {
			continue
		}
		//gbid
		apeID := row[2]
		if "" == apeID {
			//不删设备id为空的
			continue
		}

		//默认值
		lgtstr := row[11]
		if "" == lgtstr {
			lgtstr = "0"
		}
		latstr := row[12]
		if "" == latstr {
			latstr = "0"
		}
		portstr := row[19]
		if "" == portstr {
			portstr = "10000"
		}

		longitude, _ := strconv.ParseFloat(lgtstr, 64)
		latitude, _ := strconv.ParseFloat(latstr, 64)
		port, _ := strconv.Atoi(portstr)

		var t = &model.APE{
			ApeID:            apeID,
			Name:             row[0],
			Model:            row[14],
			IPAddr:           row[17],
			IPV6Addr:         row[18],
			Port:             port,
			Longitude:        longitude,
			Latitude:         latitude,
			PlaceCode:        row[10],
			Place:            "",
			OrgCode:          row[9],
			CapDirection:     0,
			MonitorDirection: "",
			MonitorAreaDesc:  "",
			IsOnline:         "",
			OwnerApsID:       "",
			UserId:           row[25],
			Password:         row[26],
			FunctionType:     "",
			PositionType:     "",
			TollgateID:       "",
			AreaType:         "",
			PassDirection:    "",
		}
		apes = append(apes, t)
	}
	logger.LOG_WARN("apes size=", len(apes))
	return apes, nil
}

func getSubscribeInfo(managerId string) map[string][]*model.Subscribe {
	subMap := make(map[string][]*model.Subscribe)
	subMap["EQUIPMENT"] = make([]*model.Subscribe, 0)
	subMap["TOLLGATE"] = make([]*model.Subscribe, 0)
	subMap["LANE"] = make([]*model.Subscribe, 0)

	subs, err := db.QuerySubscribes()
	if nil != err {
		logger.LOG_ERROR("查询订阅信息失败：", err)
		return subMap
	}

	for _, sub := range subs {
		if sub.OperateType != 0 {
			continue
		}
		if sub.SubscribeStatus != 0 && sub.SubscribeStatus != 99 {
			continue
		}
		if managerId != sub.ManagerID {
			continue
		}

		detail := "," + sub.SubscribeDetail + ","
		if strings.Index(detail, ","+constant.EQUIPMENT_LIST+",") >= 0 ||
			strings.Index(detail, ","+constant.EQUIPMENT_STATUS+",") >= 0 {
			subMap["EQUIPMENT"] = append(subMap["EQUIPMENT"], sub.Subscribe)
		}
		if strings.Index(detail, ","+constant.TOLLGATE_LIST+",") >= 0 ||
			strings.Index(detail, ","+constant.SINGLE_TOLLGATE_INFO+",") >= 0 ||
			strings.Index(detail, ","+constant.HIK_ILLEGAL+",") >= 0 {
			subMap["TOLLGATE"] = append(subMap["TOLLGATE"], sub.Subscribe)
		}
		if strings.Index(detail, ","+constant.LAND_LIST+",") >= 0 ||
			strings.Index(detail, ","+constant.SINGLE_LAND_INFO+",") >= 0 {
			subMap["LANE"] = append(subMap["LANE"], sub.Subscribe)
		}
	}

	return subMap
}
